#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <gmssl/sm2.h>
#include <gmssl/sm3.h>
#include <gmssl/sm4.h>

void print_hex(const char *label, const uint8_t *data, size_t len) {
    printf("%s: ", label);
    for (size_t i = 0; i < len; i++) {
        printf("%02X", data[i]);
    }
    printf("\n");
}

int main() {
    int ret = 0;
    FILE *envelope_file = NULL;
    uint8_t *encrypted_key = NULL;
    uint8_t *ciphertext = NULL;
    uint8_t *decrypted = NULL;

    // Step 1: 加载接收方私钥
    SM2_KEY receiver_key;
    FILE *key_file = fopen("receiver_key.pem", "rb");
    sm2_private_key_from_pem(&receiver_key, key_file); // GmSSL 3.1.1 兼容函数
    fclose(key_file);
    printf("[接收方] 已加载接收方私钥\n");

    // Step 2: 打开数字信封文件
    envelope_file = fopen("envelope.bin", "rb");
    if (!envelope_file) {
        fprintf(stderr, "[接收方] 无法打开信封文件\n");
        goto error;
    }

    // Step 3: 读取加密的对称密钥长度
    size_t encrypted_key_len;
    if (fread(&encrypted_key_len, sizeof(size_t), 1, envelope_file) != 1) {
        fprintf(stderr, "[接收方] 读取 encrypted_key_len 失败\n");
        goto error;
    }

    // Step 4: 读取加密的对称密钥
    encrypted_key = malloc(encrypted_key_len);
    if (!encrypted_key) {
        fprintf(stderr, "[接收方] 分配加密密钥内存失败\n");
        goto error;
    }
    if (fread(encrypted_key, 1, encrypted_key_len, envelope_file) != encrypted_key_len) {
        fprintf(stderr, "[接收方] 读取 encrypted_key 失败\n");
        goto error;
    }

    // Step 5: 读取 IV
    uint8_t iv[16];
    if (fread(iv, 1, sizeof(iv), envelope_file) != sizeof(iv)) {
        fprintf(stderr, "[接收方] 读取 IV 失败\n");
        goto error;
    }

    // Step 6: 读取密文长度
    size_t ciphertext_len;
    if (fread(&ciphertext_len, sizeof(size_t), 1, envelope_file) != 1) {
        fprintf(stderr, "[接收方] 读取 ciphertext_len 失败\n");
        goto error;
    }

    // Step 7: 读取密文
    ciphertext = malloc(ciphertext_len);
    if (!ciphertext) {
        fprintf(stderr, "[接收方] 分配密文内存失败\n");
        goto error;
    }
    if (fread(ciphertext, 1, ciphertext_len, envelope_file) != ciphertext_len) {
        fprintf(stderr, "[接收方] 读取 ciphertext 失败\n");
        goto error;
    }

    // Step 8: 读取哈希值
    uint8_t hash[SM3_DIGEST_SIZE];
    if (fread(hash, 1, SM3_DIGEST_SIZE, envelope_file) != SM3_DIGEST_SIZE) {
        fprintf(stderr, "[接收方] 读取哈希值失败\n");
        goto error;
    }

    fclose(envelope_file);
    envelope_file = NULL;

    // Step 9: 解密对称密钥
    uint8_t sym_key[16];
    size_t sym_key_len;
    ret = sm2_decrypt(&receiver_key, encrypted_key, encrypted_key_len, sym_key, &sym_key_len);
    if (ret != 1 || sym_key_len != 16) {
        fprintf(stderr, "[接收方] SM2 解密失败\n");
        goto error;
    }
    print_hex("[接收方] 解密后的 SM4 对称密钥", sym_key, sizeof(sym_key));

    // Step 10: 解密密文并去除填充
    SM4_KEY sm4_dec_key;
    sm4_set_decrypt_key(&sm4_dec_key, sym_key);
    decrypted = malloc(ciphertext_len);
    sm4_cbc_decrypt(&sm4_dec_key, iv, ciphertext, ciphertext_len, decrypted);

    // 检查填充有效性
    uint8_t pad_value = decrypted[ciphertext_len - 1];
    if (pad_value > 16 || pad_value == 0) {
        fprintf(stderr, "[接收方] 填充值无效\n");
        goto error;
    }
    size_t plaintext_len = ciphertext_len - pad_value;
    decrypted[plaintext_len] = '\0';
    printf("[接收方] 解密后的明文: %s\n", decrypted);

    // Step 11: 验证哈希完整性
    uint8_t hash_decrypted[SM3_DIGEST_SIZE];
    SM3_CTX sm3_ctx;
    sm3_init(&sm3_ctx);
    sm3_update(&sm3_ctx, decrypted, plaintext_len);
    sm3_finish(&sm3_ctx, hash_decrypted);
    print_hex("[接收方] 解密明文的哈希", hash_decrypted, SM3_DIGEST_SIZE);

    if (memcmp(hash, hash_decrypted, SM3_DIGEST_SIZE) == 0) {
        printf("[接收方] 哈希验证成功，数据完整\n");
    } else {
        printf("[接收方] 哈希验证失败，数据被篡改\n");
        goto error;
    }

    // 释放资源
    free(encrypted_key);
    free(ciphertext);
    free(decrypted);
    return EXIT_SUCCESS;

error:
    if (envelope_file) fclose(envelope_file);
    if (encrypted_key) free(encrypted_key);
    if (ciphertext) free(ciphertext);
    if (decrypted) free(decrypted);
    return EXIT_FAILURE;
}
